/*
 * DIM-SUM操作系统 -- EL2相关头文件
 *
 * Copyright (C) 2017 谢宝友
 *
 * 作者: Baoyou Xie <baoyou.xie@aliyun.com>
 * 			Dong Peng <w-pengdong@kernelsoft.com>	
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#ifndef __ASM_HYP_H
#define __ASM_HYP_H

#include <dim-sum/types.h>
#include <asm/sysreg.h>

#define ICC_SRE_EL2_SRE			(1 << 0)
#define ICC_SRE_EL2_ENABLE		(1 << 3)
#define SYS_PMBIDR_EL1			sys_reg(3, 0, 9, 10, 7)
#define SYS_PMSCR_EL2			sys_reg(3, 4, 9, 9, 0)
#define ID_AA64MMFR1_LOR_SHIFT		16
#define SYS_LORID_EL1			sys_reg(3, 0, 10, 4, 7)
#define SYS_LORC_EL1			sys_reg(3, 0, 10, 4, 3)
#define SYS_PMBIDR_EL1_P_SHIFT		4
#define SYS_PMSCR_EL2_PCT_SHIFT		6
#define SYS_PMSCR_EL2_PA_SHIFT		4
#define MDCR_EL2_E2PB_MASK	(UL(0x3))
#define MDCR_EL2_E2PB_SHIFT	(UL(12))
#define MDCR_EL2_TPMS		(1 << 14)
#define BOOT_CPU_MODE_EL1	(0xe11)
#define BOOT_CPU_MODE_EL2	(0xe12)

#define SCTLR_EL1_RES1	((1 << 11) | (1 << 20) | (1 << 22) | (1 << 28) | \
			 (1 << 29))
#define SCTLR_EL2_RES1	((1 << 4)  | (1 << 5)  | (1 << 11) | (1 << 16) | \
			 (1 << 18) | (1 << 22) | (1 << 23) | (1 << 28) | \
			 (1 << 29))

#define ENDIAN_SET_EL1		0
#define ENDIAN_SET_EL2		0
#define BOOT_CPU_MODE_EL1	(0xe11)
#define CurrentEL_EL1		(1 << 2)
#define CurrentEL_EL2		(2 << 2)

/* hypervisor配置寄存器相关 */
#define HCR_FWB		(UL(1) << 46)
#define HCR_API		(UL(1) << 41)
#define HCR_APK		(UL(1) << 40)
#define HCR_TEA		(UL(1) << 37)
#define HCR_TERR	(UL(1) << 36)
#define HCR_TLOR	(UL(1) << 35)
#define HCR_E2H		(UL(1) << 34)
#define HCR_ID		(UL(1) << 33)
#define HCR_CD		(UL(1) << 32)
#define HCR_RW_SHIFT	31
#define HCR_RW		(UL(1) << HCR_RW_SHIFT)
#define HCR_TRVM	(UL(1) << 30)
#define HCR_HCD		(UL(1) << 29)
#define HCR_TDZ		(UL(1) << 28)
#define HCR_TGE		(UL(1) << 27)
#define HCR_TVM		(UL(1) << 26)
#define HCR_TTLB	(UL(1) << 25)
#define HCR_TPU		(UL(1) << 24)
#define HCR_TPC		(UL(1) << 23)
#define HCR_TSW		(UL(1) << 22)
#define HCR_TAC		(UL(1) << 21)
#define HCR_TIDCP	(UL(1) << 20)
#define HCR_TSC		(UL(1) << 19)
#define HCR_TID3	(UL(1) << 18)
#define HCR_TID2	(UL(1) << 17)
#define HCR_TID1	(UL(1) << 16)
#define HCR_TID0	(UL(1) << 15)
#define HCR_TWE		(UL(1) << 14)
#define HCR_TWI		(UL(1) << 13)
#define HCR_DC		(UL(1) << 12)
#define HCR_BSU		(3 << 10)
#define HCR_BSU_IS	(UL(1) << 10)
#define HCR_FB		(UL(1) << 9)
#define HCR_VSE		(UL(1) << 8)
#define HCR_VI		(UL(1) << 7)
#define HCR_VF		(UL(1) << 6)
#define HCR_AMO		(UL(1) << 5)
#define HCR_IMO		(UL(1) << 4)
#define HCR_FMO		(UL(1) << 3)
#define HCR_PTW		(UL(1) << 2)
#define HCR_SWIO	(UL(1) << 1)
#define HCR_VM		(UL(1) << 0)

#define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK)
#define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)

#define Op0_shift	19
#define Op0_mask	0x3
#define Op1_shift	16
#define Op1_mask	0x7
#define CRn_shift	12
#define CRn_mask	0xf
#define CRm_shift	8
#define CRm_mask	0xf
#define Op2_shift	5
#define Op2_mask	0x7


#define ID_AA64PFR0_SVE_SHIFT		32
#define SYS_ZCR_EL2			sys_reg(3, 4, 1, 2, 0)

/* AArch64 SPSR */
#define PSR_F_BIT	0x00000040
#define PSR_I_BIT	0x00000080
#define PSR_A_BIT	0x00000100
#define PSR_D_BIT	0x00000200
#define PSR_SSBS_BIT	0x00001000
#define PSR_PAN_BIT	0x00400000
#define PSR_UAO_BIT	0x00800000
#define PSR_DIT_BIT	0x01000000
#define PSR_V_BIT	0x10000000
#define PSR_C_BIT	0x20000000
#define PSR_Z_BIT	0x40000000
#define PSR_N_BIT	0x80000000

/*
 * PSR
 */
#define PSR_MODE_EL0t	0x00000000
#define PSR_MODE_EL1t	0x00000004
#define PSR_MODE_EL1h	0x00000005
#define PSR_MODE_EL2t	0x00000008
#define PSR_MODE_EL2h	0x00000009
#define PSR_MODE_EL3t	0x0000000c
#define PSR_MODE_EL3h	0x0000000d
#define PSR_MODE_MASK	0x0000000f
#define CPTR_EL2_TZ	(1 << 8)
#define ZCR_ELx_LEN_MASK	0x1ff
#define sys_reg(op0, op1, crn, crm, op2) \
	(((op0) << Op0_shift) | ((op1) << Op1_shift) | \
	 ((crn) << CRn_shift) | ((crm) << CRm_shift) | \
	 ((op2) << Op2_shift))
#define SYS_ICC_SRE_EL2			sys_reg(3, 4, 12, 9, 5)
#define SYS_ICH_HCR_EL2			sys_reg(3, 4, 12, 11, 0)


#define HVC_SET_VECTORS 0
#define HVC_SOFT_RESTART 1
#define HVC_RESET_VECTORS 2
#define HVC_STUB_ERR	0xbadca11

#ifndef __ASSEMBLY__

asm(
	"	.irp	num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n"
	"		.equ	.L__reg_num_x\\num, \\num\n"
	"	.endr\n"
	"\n"
	"	.equ	.L__reg_num_xzr, 31\n"
	"\n"
);

#define read_sysreg(reg) ({			\
	u64 val;		\
	asm volatile("mrs_s %0, " __stringify(reg) : "=r" (val));	\
	val;			\
})

#define write_sysreg(val, reg)			\
	asm volatile("msr_s " __stringify(reg) ", %0"		\
		     : : "r" ((u64)(val)))

extern u32 __boot_cpu_mode[2];

void __hyp_set_vectors(phys_addr_t phys_vector_base);
void __hyp_reset_vectors(void);

static inline bool is_hyp_mode_available(void)
{
	return (__boot_cpu_mode[0] == BOOT_CPU_MODE_EL2 &&
		__boot_cpu_mode[1] == BOOT_CPU_MODE_EL2);
}

static inline bool is_kernel_in_hyp_mode(void)
{
	u64 __val;
	asm volatile("mrs %0, " "CurrentEL" : "=r" (__val));;
	return __val == CurrentEL_EL2;
}

void arch_kvm_init(void);
int kvm_arch_init(void);

#endif /* __ASSEMBLY__ */

#endif /* __ASM_HYP_H */
